package com.car.utils;

import com.car.config.DataSourceConfig;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class JDBCUtils {
    //  //声明了一个静态的日志对象 log，用于记录日志信息。
    private static final Log log = LogFactory.getLog(JDBCUtils.class);
    //ERROR：表示错误级别的日志，用于记录严重的错误事件，可能会导致程序无法继续运行。
    //WARN：表示警告级别的日志，用于记录可能会引起问题的情况，但不会导致程序终止。
    //INFO：表示信息级别的日志，用于记录一般的程序执行信息，如启动信息、连接数据库信息等。
    //DEBUG：表示调试级别的日志，用于输出详细的调试信息，可用于排查问题和调试。
    //TRACE：表示跟踪级别的日志，输出最详细的日志信息，通常用于追踪程序的详细执行过程。


    /**
     * 预编译对象
     *
     * @param sql    sql
     * @param params 参数
     * @return 预编译对象
     */
    public static PreparedStatement createPreparedStatement(String sql, Object... params) throws Exception {

        //获取连接对象
        Connection connection = DataSourceConfig.getConnection();
        //创建预编译对象    防止 SQL 注入攻击,提高性能,代码可读性和维护性
        PreparedStatement ps = connection.prepareStatement(sql);
        //获取元数据       通过获取元数据，可以了解查询结果集的结构，包括字段名、字段类型等信息
        ParameterMetaData parameterMetaData = ps.getParameterMetaData();
        //获取字符串需要的参数个数 ->问号的个数
        int parameterCount = parameterMetaData.getParameterCount();
        //问号的个数和sql参数的个数长度要一致
        if (params.length != parameterCount) {
            log.info("JDBCUtils=>SQL参数不一致,sql=>" + ps + ",参数:" + Arrays.toString(params));
            throw new RuntimeException("SQL参数不一致");
        }
        //判断什么情况下赋值
        for (int i = 1; i <= params.length; i++) {
            //setObject 用于设置 SQL 语句中的参数值
            ps.setObject(i, params[i - 1]);
        }
        //日志信息
        log.info("JDBCUtils=>" + ps);
        return ps;
    }

    /**
     * sql DML DDL 语句
     *
     * @param sql
     * @param params
     * @throws Exception
     */
    public static int update(String sql, Object... params) throws Exception {
        //预编译对象
        PreparedStatement ps = createPreparedStatement(sql, params);
        //执行sql
        int i = ps.executeUpdate();
        log.info("影响记录时:" + i);
        //todo：关闭资源
        return i;
    }

    /**
     * 根据查询数据，封装成对应的实体类
     *
     * @param sql    sql
     * @param c      类型
     * @param params 参数
     * @param <T>    泛型T
     * @return 实体类
     * @throws Exception 异常
     */
    public static <T> T query(String sql, Class<T> c, Object... params) throws Exception {
        //预编译对象
        PreparedStatement ps = createPreparedStatement(sql, params);
        //执行sql
        ResultSet resultSet = ps.executeQuery();
        //获取数据库表字段
        ResultSetMetaData metaData = resultSet.getMetaData();
        //循环获取字段值
        T res =null;
        //指向记录
        if (resultSet.next()) {
             res = c.getConstructor().newInstance();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                //用于设置 JavaBean 对象的属性值。它通过反射的方式，根据属性名将对应的值设置到对象中
                //metaData.getColumnName(i) 获取结果集中第 i 列的列名。
                //resultSet.getObject(i) 获取结果集中第 i 列的值。
                BeanUtils.setProperty(res, toConvertFiledName(metaData.getColumnName(i)), resultSet.getObject(i));
            }

        }
        return res;
    }
    /**
     * 提高代码的一致性、可读性和可维护性
     * toConvertFiledName(String fileName)：
     * 这个私有方法将数据库列名从蛇形命名转换为驼峰命名。
     * 它在query方法内部使用，将列名转换为对应的Java字段名。
     *
     * @param fileName
     * @return
     */
    private static String toConvertFiledName(String fileName) {
        if (!fileName.contains("_")) {
            return fileName;
        }
        StringBuilder sb = new StringBuilder();
        String[] split = fileName.split("_");
        sb.append(split[0]);
        for (int i = 1; i < split.length; i++) {
            char c = (char) (split[i].charAt(0) - 32);
            sb.append(c + split[i].substring(1, split[i].length()));
        }

        return sb.toString();
    }
    /**
    @SafeVarargs
    public static <E extends AutoCloseable> void close(E ...es) throws Exception {
        for(E e :es){
            if (e!=null){
                e.close();
            }
        }
    }
*/
    /**
     * 执行提供的SQL查询，并返回一个填充了对象列表。
     *
     * @param sql    SQL查询语句
     * @param c      结果映射的类
     * @param params 查询参数
     * @return 填充好的对象列表
     */
    public static <T> List<T> querylist(String sql, Class<T> c, Object... params) throws Exception {
        PreparedStatement ps = createPreparedStatement(sql, params);
        ResultSet resultSet = ps.executeQuery();
        ResultSetMetaData metaData = resultSet.getMetaData();
        List<T> list = new ArrayList<>();
        while (resultSet.next()) {
            T res = c.getConstructor().newInstance();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                BeanUtils.setProperty(res, toConvertFiledName(metaData.getColumnName(i)), resultSet.getObject(i));
            }
            list.add(res);
        }
        return list;
    }

}




    






